#pragma once
#include <mutex>
//1.RAII 资源的生命周期跟智能指针的生命周期一样 基本不存在内存泄漏
// 
//2、像指针一样
//3、拷贝问题
namespace yc
{
	template<class T>
	class auto_ptr
	{
	public:
		//RAII 保存资源
		auto_ptr(T* ptr) :_ptr(ptr)
		{}
		//释放资源
		~auto_ptr()
		{
			//delete[] _ptr;
			delete _ptr;
			cout << _ptr << endl;
		}
		//
		auto_ptr(auto_ptr<T>& p)
			:_ptr(p._ptr)
		{
			p._ptr = nullptr;
		}
		//像指针一样
		T& operator*()
		{
			return *_ptr;
		}
		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};



	template<class T>
	class unique_ptr
	{
	public:
		//RAII 保存资源
		unique_ptr(T* ptr) :_ptr(ptr)
		{}
		//释放资源
		~unique_ptr()
		{
			//delete[] _ptr;
			delete _ptr;
			cout << _ptr << endl;
		}
		//
		unique_ptr(unique_ptr<T>& p) = delete;
		unique_ptr<T>& operator=(unique_ptr<T>& p) = delete;
		//像指针一样
		T& operator*()
		{
			return *_ptr;
		}
		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};



	template<class T>
	class shared_ptr
	{
	public:
		//RAII 保存资源
		shared_ptr(T* ptr) :_ptr(ptr),_pcount(new int(1)),_pmtx(new mutex)
		{}
		//释放资源
		~shared_ptr()
		{
			//delete[] _ptr;
			Release();
		}
		//
		void Release()
		{
			_pmtx->lock();

			if (--(*_pcount) == 0)
			{
				delete _ptr;
				delete _pcount;
				cout << _ptr << endl;
			}
			_pmtx->unlock();
		}
		int use_count() const 
		{
			return *_pcount;
		}
		shared_ptr(const shared_ptr<T>& p)
			:_ptr(p._ptr)
			,_pcount(p._pcount)
			,_pmtx(p._pmtx)
		{
			//_pmtx->lock();
			++(*_pcount);
			//_pmtx->unlock();

		}
		//赋值的情况需要注意以下两种特殊情况
		//sp1 = sp2
		//sp1 = sp1
		shared_ptr<T>& operator=(shared_ptr<T>& p)
		{
			//因为很多指的是同一块儿资源，所以需要比较资源的地址
			if (_ptr != p._ptr)
			{
				//需要先释放
				int flag = false;
				_pmtx->lock();
				if (--(*_pcount) == 0)
				{
					delete _pcount;
					delete _ptr;
					flag = true;
				}
				_pmtx->unlock();
				_pcount = p._pcount;
				_ptr = p._ptr;
				++(*p._pcount);
				if (flag)
					delete _pmtx;
				return *this;
			}
		}
		T* Get() const 
		{
			return _ptr;
		}
		//像指针一样
		T& operator*()
		{
			return *_ptr;
		}
		T& operator[](size_t pos)
		{
			return _ptr[pos];
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pcount;    //不能是静态的，如果是两块资源的话，静态的属于整个类，属于类的所有对象，其中一块资源只有一个指针指向
		mutex* _pmtx;

	};

	//weak_ptr
	template<class T>
	class weak_ptr
	{
		weak_ptr(const shared_ptr<int> &p ):_ptr(p.Get()){}
		weak_ptr() :_ptr(nullptr) {}

		weak_ptr<T>& operator=(const shared_ptr<int>& p)
		{
			_ptr = p.Get();
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;

	}



	struct Date
	{
		int _year = 0;
		int _month = 0;
		int _day = 0;
	};





	// shared_ptr 本身是线程安全的，拷贝和析构时，引用计数++，是线程安全的
	//shared_ptr 管理资源的饿访问不是线程安全的，需要用的地方自行保护
	void test_share_ptr()
	{
		int n = 50000;
		mutex mtx;
		std::shared_ptr<Date> sp1(new Date);

		thread t1([&]()   //lambda 表达式  thread t1([&]() {});
		{
			for (int i = 0; i < n; ++i)
			{
				std::shared_ptr<Date> sp2(sp1);
				mtx.lock();
				sp2->_year++;
				sp2->_day++;
				sp2->_month++;
				mtx.unlock();
			}
		});
		thread t2([&]()
		{
			for (int i = 0; i < n; ++i)
			{
				std::shared_ptr<Date> sp3(sp1);
				mtx.lock();
				sp3->_year++;
				sp3->_day++;
				sp3->_month++;
				mtx.unlock();
			}
		});
		t1.join();
		t2.join();
		cout << sp1.use_count() << endl;
		cout << sp1.get() << endl;
		cout << sp1->_year << endl;
		cout << sp1->_month << endl;
		cout << sp1->_day << endl;
	
	}

	struct ListNode
	{
		int val;
		//ListNode* _next;
		//ListNode* _prev;
		//std::shared_ptr<ListNode> _next;
		//std::shared_ptr<ListNode> _prev;   //只要是循环引用，就会出错，单向引用是可以的

		//为此引入了weak_ptr协助shared_ptr进行协助管理,weak_ptr不进行资源的管理，只负责指向,不增加引用计数
		//不接受指针，不支持RAII
		std::weak_ptr<ListNode> _next;
		std::weak_ptr<ListNode> _prev;
		~ListNode()
		{
			cout << "~ListNode" << endl;
		}
	};

	void test2()
	{
		std::shared_ptr<ListNode> n1(new ListNode);
		std::shared_ptr<ListNode> n2(new ListNode);

		n1->_next = n2;
		n2->_prev = n1;
		cout << n1.use_count() << endl;
		cout << n2.use_count() << endl;

	}


}